package com.wolfking.converter.dropdown;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.wolfking.converter.config.DynamicDataSourceContext;
import com.wolfking.converter.service.JdbcTemplateService;
import com.wolfking.converter.util.ConverterSpringContext;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.jdbc.support.rowset.SqlRowSetMetaData;

import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Slf4j
public class SqlQueryParameterDropDown implements ParameterDropDown {

    private Config config;


    private static final Cache<Config, Map<String, String>> QUERY_CACHE = CacheBuilder.newBuilder()
            .expireAfterWrite(10, TimeUnit.SECONDS).maximumSize(10000)
            .concurrencyLevel(100)
            .build();

    private static final Cache<Config, Map<String, String>> QUERY_CACHE_LONG = CacheBuilder.newBuilder()
            .expireAfterWrite(1, TimeUnit.MINUTES).maximumSize(10000)
            .concurrencyLevel(100)
            .build();

    public SqlQueryParameterDropDown(String cons) {
        Gson gson = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
        try {
            config = gson.fromJson(cons, Config.class);
        } catch (Exception e) {
            config = new Config();
            config.setSql(cons);
        }
    }

    @Override
    public Map<String, String> buildParameterDropDown() {
        Map<String, String> oneCache = QUERY_CACHE_LONG.getIfPresent(config);
        if (Objects.nonNull(oneCache)) {
            log.info("{} hit long cache {}", config.getSql(), oneCache);
            return oneCache;
        }
        Map<String, String> o = QUERY_CACHE.getIfPresent(config);
        if (Objects.nonNull(o)) {
            log.info("{} hit empty cache {}", config.getSql(), o);
            return o;
        }
        try {
            Map<String, String> downMap = Maps.newHashMap();
            DynamicDataSourceContext dynamicDataSourceContext = ConverterSpringContext.getBean(DynamicDataSourceContext.class);
            JdbcOperations jdbcTemplate = ConverterSpringContext.getBean(JdbcTemplateService.class).getJdbcTemplate();
            dynamicDataSourceContext.setDataSourceType(config.getDatasource());
            SqlRowSet sqlRowSet = jdbcTemplate.queryForRowSet(config.getSql());
            SqlRowSetMetaData metaData = sqlRowSet.getMetaData();
            while (sqlRowSet.next()) {
                String value = sqlRowSet.getString(1);
                String desc = value;
                if (metaData.getColumnCount() > 1) {
                    desc = sqlRowSet.getString(2);
                }
                downMap.put(value, desc);
            }
            if (downMap.isEmpty()) {
                QUERY_CACHE.put(config, downMap);
            } else {
                QUERY_CACHE_LONG.put(config, downMap);
            }
            return downMap;
        } catch (Exception e) {
            log.warn("", e);
            QUERY_CACHE.put(config, Maps.newHashMap());
            return Maps.newHashMap();
        }
    }

    @Data
    private static class Config {
        String sql;
        String datasource;
    }
}
